package com.lzw.DailyAudit.service.dateAggregation_02.DailyAudit.service.issueReports_04;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.hooya.fa.eu.biz.DailyAudit.entity.CheckProfitBO;
import com.hooya.fa.eu.biz.DailyAudit.entity.DailyAuditStatus;
import com.hooya.fa.eu.biz.DailyAudit.entity.ProfitCheckRecord;
import com.hooya.fa.eu.biz.DailyAudit.entity.ProfitStatement;
import com.hooya.fa.eu.biz.DailyAudit.entity.dto.ProfitCheckDTO;
import com.hooya.fa.eu.biz.DailyAudit.entity.dto.ProfitStatementDaily;
import com.hooya.fa.eu.biz.DailyAudit.mapper.*;
import com.hooya.fa.eu.biz.DailyAudit.service.dateAggregation_02.CommonService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ProfitCheck {

    @Autowired
    private DailyStkOrigDataCollectMapper dailyStkOrigDataCollectMapper;

    @Autowired
    private DailyMetaExchangePlMapper dailyMetaExchangePlMapper;

    @Autowired
    private CommonService commonService;

    @Autowired
    private DailyAuditStatusMapper statusMapper;

    @Autowired
    private DailyProfitCheckMapper profitCheckMapper;

    @Autowired
    private DailyTempKcjlDailyMapper tempKcjlDailyMapper;

    @Autowired
    private IdentifierGenerator identifierGenerator;


    private static final String[] SECOND_COLUMNS = {"index", "SKU", "invoice_number", "invoice_date", "inbound_date", "begin_of_the_month_stock", "end_of_the_month_stock", "inbound", "sales", "transfer", "lost", "restock", "in_price_eur", "in_price_usd", "currency_rate", "PLN", "type", "flag", "level_0", "in_price_usd_x", "transfer_y"};

    private static final String[] PROFIT_COLUMNS = {"SKU", "invoice_number", "invoice_date", "inbound_date", "begin_of_the_month_stock", "end_of_the_month_stock", "inbound", "sales", "transfer", "lost", "restock", "in_price_eur", "in_price_usd", "currency_rate", "PLN", "type", "flag","belongs"};

    private static final List<String> COMPANY_LIST = Arrays.asList("costway-fr", "costway-it", "costway-pl", "costway-de");

    private static final String PATH = "./profit_check/";


    /**
     * 主方法
     */
    public void profitCheck(String start) {
        try {

            String name = "profitCheck-04";
            DailyAuditStatus dailyAuditStatus = statusMapper.selectStatus(name, start);
            if (dailyAuditStatus != null && dailyAuditStatus.getFlag() == 1) {
                log.info("{} - 该方法已执行，进行跳过！", name);
                return;
            }

            //获取明天的时间作为截止时间
            LocalDate endDate = LocalDate.parse(start, DateTimeFormatter.ofPattern("yyyy-MM-dd")).plusDays(1); // 如start:08-01  则endDate:08-02
            String end = endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); //08-02
            String currDate = start.replace("-", ""); //20250801  那月和日拼接

            String dir = commonService.joinDate(PATH, start);
            // 创建输出目录
            commonService.createDirectories(dir);
            //创建接收_sub的数据集合
            List<ProfitCheckDTO> allData = new ArrayList<>();

            // 第一流程 -- 完成   示例： 这里会读取profit_check/xx年/xx月/xx日/costway-de_20251001.csv
            for (String company : COMPANY_LIST) {
                List<ProfitCheckDTO> reduceOutData = firstFlow(start, end, company);  // 处理数据
                allData.addAll(reduceOutData);
            }

            // 第二流程 -- 完成
            for (String company : COMPANY_LIST) {
                log.info(company);
                String savePath = dir + "/" + company + "_" + currDate + ".csv";
                List<ProfitCheckDTO> afterDealData = secondFlow(allData, company);  // 整理数据
                // 将数据写入CSV文件
                writeSecondFlowCsvFile(afterDealData, savePath);
            }

			// 修改执行状态
            commonService.UpdateOrInsertStatus(dailyAuditStatus, name, start);

            System.out.println("利润检查表生成完毕");
        } catch (Exception e) {
            log.error("处理ProfitCheck数据时发生错误", e);
            throw new RuntimeException("处理ProfitCheck数据时发生错误", e);
        }
    }

    /**
     * 第一流程处理
     */
    private List<ProfitCheckDTO> firstFlow(String start, String end, String company) {
        // 上个月数据
        List<ProfitCheckDTO> prevData = getPrevData(start, company, PATH);  // 对于这些cvs数据，可以考虑设计数据库存储，数据存储到数据库中方便读写

        // 当月采购、报损、b2b数据
        List<ProfitCheckDTO> inData = unitInData(start, end, company);

        Map<String, List<ProfitCheckDTO>> dealPriceMap = dealPrice(inData);
        inData = dealPriceMap.get("priceData");
        List<ProfitCheckDTO> noPriceData = dealPriceMap.get("noPriceData");

        if (CollectionUtil.isNotEmpty(noPriceData)) {
            log.error("存在没有价格的数据");
            throw new RuntimeException("存在没有价格数据");
        }

        List<ProfitCheckDTO> allInData = new ArrayList<>(prevData);
        allInData.addAll(inData);

        // 转换日期格式 -- 将其统一为 yyyy-MM-dd -- 用于排序
		changeDateFormatter(allInData);


		List<ProfitCheckDTO> reduceOutData = dealOutData(allInData, start, end, company);
        reduceOutData.forEach(f -> {
            f.setCompany(company);
            f.setInbound(f.getInbound() == null ? 0 : f.getInbound());
            f.setSales(f.getSales() == null ? 0 : f.getSales());
            f.setLost(f.getLost() == null ? 0 : f.getLost());
            f.setRestock(f.getRestock() == null ? 0 : f.getRestock());
            f.setTransfer(f.getTransfer() == null ? 0 : f.getTransfer());
            f.setCreatetime(Date.from(LocalDateTime.now().atZone(java.time.ZoneId.systemDefault()).toInstant()));
        });

        return reduceOutData;
    }

	private static void changeDateFormatter(List<ProfitCheckDTO> allInData) {
		allInData.forEach(dto -> {
			String dateStr = dto.getInboundDate();
			if (dateStr == null || dateStr.isEmpty()) {
				return;
			}

			// 检查是否已经是 yyyy-MM-dd 格式
			DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
			try {
				LocalDate.parse(dateStr, formatter1);
				// 已经是正确格式，不修改
				return;
			} catch (DateTimeParseException e) {
				// 不是 yyyy-MM-dd 格式，尝试解析 yyyy/M/d
			}

			// 尝试解析 yyyy/M/d 格式
			DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy/M/d");
			try {
				LocalDate parsedDate = LocalDate.parse(dateStr, formatter2);
				dto.setInboundDate(parsedDate.format(formatter1)); // 转换为 yyyy-MM-dd
			} catch (DateTimeParseException e) {
				log.warn("无法解析日期: {}", dateStr);
			}
		});
	}

	/**
     * 获取前一天的数据
     */
    private List<ProfitCheckDTO> getPrevData(String start, String company, String path) {
        // 获取前一天
        String prevLast = commonService.getPrevDate(start);
        String dir = commonService.joinDate(path, prevLast);

        String prevDate = prevLast.replace("-", "");  // 那对应报表的数据 - 20250731
        String dataPath = dir + "/" + company + "_" + prevDate + ".csv";

        List<ProfitCheckDTO> prevData = new ArrayList<>();
        try (BufferedReader br = new BufferedReader(new InputStreamReader(Files.newInputStream(Paths.get(dataPath)), "GBK"))) {
            String line;
            String[] headers = null;
            int lineCount = 0;

            while ((line = br.readLine()) != null) {
                String[] values = line.split(",");

                // 第一行是标题
                if (lineCount == 0) {
                    headers = values;
                    lineCount++;
                    continue;
                }

                // 创建一个Map来存储标题和值的对应关系
                Map<String, String> rowMap = new HashMap<>();
                for (int i = 0; i < headers.length && i < values.length; i++) {
                    rowMap.put(headers[i].trim(), values[i].trim());
                }

                // 只处理 end_of_the_month_stock > 0 的数据
                String endOfMonthStockStr = rowMap.get("end_of_the_month_stock");
                if (endOfMonthStockStr != null && !endOfMonthStockStr.isEmpty()) {
                    try {
                        // 保存原始字符串用于日志记录
                        int endOfMonthStock = Integer.parseInt(commonService.cleanString(endOfMonthStockStr));

                        if (endOfMonthStock > 0) {
                            ProfitCheckDTO dto = new ProfitCheckDTO();

                            // 设置需要的字段
                            dto.setSku(rowMap.get("SKU"));
                            dto.setInvoiceNumber(rowMap.get("invoice_number"));
                            dto.setInvoiceDate(rowMap.get("invoice_date"));
                            dto.setInboundDate(rowMap.get("inbound_date"));
                            dto.setEndOfMonthStock(endOfMonthStock);

                            // 安全地解析Double值，处理空字符串情况
                            String currencyRateStr = rowMap.get("currency_rate");
                            if (currencyRateStr != null && !currencyRateStr.isEmpty() && !"null".equals(currencyRateStr)) {
                                dto.setCurrencyRate(Double.valueOf(currencyRateStr));
                            } else {
                                dto.setCurrencyRate(null);
                            }

                            String plnStr = rowMap.get("PLN");
                            if (plnStr != null && !plnStr.isEmpty() && !"null".equals(plnStr)) {
                                dto.setPln(Double.valueOf(plnStr));
                            } else {
                                dto.setPln(null);
                            }

                            dto.setType(rowMap.get("type"));

                            // 将 end_of_the_month_stock 赋值给 begin_of_the_month_stock
                            dto.setBeginOfMonthStock(endOfMonthStock);

                            // 设置价格相关信息
                            Double inPriceEur = commonService.parseDoubleValue(rowMap.get("in_price_eur"));
                            Double inPriceUsd = commonService.parseDoubleValue(rowMap.get("in_price_usd"));

                            // 当 in_price_eur 不为 null 时，in_price_usd 设为 null
                            if (inPriceEur != null) {
                                inPriceUsd = null;
                            }
                            dto.setInPriceEur(inPriceEur);
                            dto.setInPriceUsd(inPriceUsd);

                            // 设置其他字段为0
                            dto.setInbound(0);
                            dto.setSales(0);
                            dto.setRestock(0);
                            dto.setLost(0);
                            dto.setTransfer(0);

                            prevData.add(dto);
                        }
                    } catch (NumberFormatException e) {
                        log.warn("解析end_of_the_month_stock数值时出错: {}，原始字符串: '{}'", endOfMonthStockStr, rowMap.get("end_of_the_month_stock"), e);
                    }
                }

                lineCount++;
            }
        } catch (IOException e) {
            log.error("读取前一个月数据文件时出错: {}", dataPath, e);
        }

        return prevData;
    }

    /**
     * 整合入库数据
     */
    private List<ProfitCheckDTO> unitInData(String start, String end, String company) {
        List<ProfitCheckDTO> cgIn = dailyStkOrigDataCollectMapper.getCgInData(start, end, company);
        if (CollectionUtil.isNotEmpty(cgIn)) {
            cgIn.forEach(f -> {
                f.setBeginOfMonthStock(0);
                f.setEndOfMonthStock(f.getInbound());
                f.setSales(0);
                f.setLost(0);
                f.setTransfer(0);
                f.setExchangedate(commonService.getPrevDate(f.getInvoiceDate()));
            });
        }

        List<ProfitCheckDTO> bsIn = dailyStkOrigDataCollectMapper.getBsInData(start, end, company);
        if (CollectionUtil.isNotEmpty(bsIn)) {
            List<ProfitCheckDTO> processedBsIn = new ArrayList<>();
            // 按SKU、inboundDate、price、currency、type分组
            Map<String, List<ProfitCheckDTO>> groupedBsIn = bsIn.stream().collect(Collectors.groupingBy(dto -> dto.getSku() + "|" + dto.getInboundDate() + "|" + dto.getPrice() + "|" + dto.getCurrency() + "|" + dto.getType()));

            // 对每组数据进行聚合处理
            for (Map.Entry<String, List<ProfitCheckDTO>> entry : groupedBsIn.entrySet()) {
                List<ProfitCheckDTO> group = entry.getValue();
                if (!group.isEmpty()) {
                    // 创建新的DTO对象
                    ProfitCheckDTO aggregatedDto = new ProfitCheckDTO();
                    BeanUtil.copyProperties(group.get(0), aggregatedDto);

                    // 计算聚合值（对restock求和）
                    int totalRestock = group.stream().mapToInt(ProfitCheckDTO::getRestock).sum();

                    // 设置聚合后的值
                    aggregatedDto.setRestock(totalRestock);
                    aggregatedDto.setBeginOfMonthStock(0);
                    aggregatedDto.setEndOfMonthStock(totalRestock);
                    aggregatedDto.setSales(0);
                    aggregatedDto.setLost(0);
                    aggregatedDto.setTransfer(0);
                    aggregatedDto.setExchangedate(commonService.getPrevDate(aggregatedDto.getInboundDate()));
                    processedBsIn.add(aggregatedDto);
                }
            }
            bsIn = processedBsIn;
        }

        List<ProfitCheckDTO> b2bIn = dailyStkOrigDataCollectMapper.getB2bInData(start, end, company);
        b2bIn.forEach(f -> {
            f.setExchangedate(commonService.getPrevDate(end));
            f.setFlag("");
        });

        List<ProfitCheckDTO> zyIn = dailyStkOrigDataCollectMapper.getzyInData(start, end, company);
        List<ProfitCheckDTO> B2bAndZyIn = new ArrayList<>(b2bIn);
        B2bAndZyIn.addAll(zyIn);
        if (CollectionUtil.isNotEmpty(B2bAndZyIn)) {
            List<ProfitCheckDTO> processedB2bAndZyIn = new ArrayList<>();
            // 按SKU、inboundDate、price、currency、type分组
            Map<String, List<ProfitCheckDTO>> groupedB2bAndZyIn = B2bAndZyIn.stream().collect(Collectors.groupingBy(dto -> dto.getSku() + "|" + dto.getInboundDate() + "|" + dto.getPrice() + "|" + dto.getInvoiceNumber() + "|" + dto.getInvoiceDate() + "|" + dto.getCurrency() + "|" + dto.getType() + "|" + dto.getExchangedate() + "|" + dto.getFlag()));

            // 对每组数据进行聚合处理
            for (Map.Entry<String, List<ProfitCheckDTO>> entry : groupedB2bAndZyIn.entrySet()) {
                List<ProfitCheckDTO> group = entry.getValue();
                if (!group.isEmpty()) {
                    // 创建新的DTO对象
                    ProfitCheckDTO aggregatedDto = new ProfitCheckDTO();
                    BeanUtil.copyProperties(group.get(0), aggregatedDto);

                    // 计算聚合值（对restock求和）
                    int totalInbound = group.stream().mapToInt(ProfitCheckDTO::getInbound).sum();

                    // 设置聚合后的值
                    aggregatedDto.setInbound(totalInbound);
                    aggregatedDto.setBeginOfMonthStock(0);
                    aggregatedDto.setEndOfMonthStock(totalInbound);
                    aggregatedDto.setSales(0);
                    aggregatedDto.setLost(0);
                    aggregatedDto.setTransfer(0);
                    processedB2bAndZyIn.add(aggregatedDto);
                }
            }
            B2bAndZyIn = processedB2bAndZyIn;
        }


        List<ProfitCheckDTO> inData = new ArrayList<>(cgIn);
        inData.addAll(bsIn);
        inData.addAll(B2bAndZyIn);

        return inData;
    }

    /**
     * 处理价格数据
     */
    private Map<String, List<ProfitCheckDTO>> dealPrice(List<ProfitCheckDTO> data) {
        Map<String, List<ProfitCheckDTO>> result = new HashMap<>();

        // 获取汇率数据
        List<ProfitCheckDTO> exchangeList = dailyMetaExchangePlMapper.getDataForProFitCheck();

        List<ProfitCheckDTO> priceData = new ArrayList<>();
        List<ProfitCheckDTO> noPriceData = new ArrayList<>();
        // 分离有价格和无价格的数据
        for (ProfitCheckDTO item : data) {
            if (item.getPrice() == null) {
                noPriceData.add(item);
            } else {
                priceData.add(item);
            }
        }

        // 检查有价格的数据中currency是否为null
        boolean hasNullCurrency = priceData.stream().anyMatch(dto -> dto.getCurrency() == null || dto.getCurrency().isEmpty());
        if (hasNullCurrency) {
            log.error("价格数据中存在currency为空的数据");
            throw new IllegalArgumentException("价格数据中存在currency为空的情况");
        }
        // 打印无价格数据信息（如果存在）
        if (!noPriceData.isEmpty()) {
            log.info("发现{}条无进仓价格的数据,数据为{}", noPriceData.size(), noPriceData);
        }

        Map<String, List<ProfitCheckDTO>> exchangeListMap = exchangeList.stream().collect(Collectors.groupingBy(ProfitCheckDTO::getRatedate));

        List<ProfitCheckDTO> eurData = priceData.stream().filter(f -> "EUR".equals(f.getCurrency())).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(eurData)) {
            List<ProfitCheckDTO> withDescription = new ArrayList<>();
            for (ProfitCheckDTO mainItem : eurData) {
                String key = mainItem.getExchangedate();
                if (exchangeListMap.containsKey(key)) {
                    List<ProfitCheckDTO> ProfitCheckDTOS = exchangeListMap.get(key);
                    ProfitCheckDTOS.forEach(f -> {
                        ProfitCheckDTO newItem = new ProfitCheckDTO();
                        BeanUtil.copyProperties(mainItem, newItem);
                        newItem.setUsdplnrate(f.getUsdplnrate());
                        newItem.setEurplnrate(f.getEurplnrate());
                        double pln = Math.round(newItem.getPrice() * newItem.getEurplnrate() * 100.0) / 100.0;
                        newItem.setPln(pln);
                        newItem.setInPriceUsd(null);
                        newItem.setCurrencyRate(newItem.getEurplnrate());
                        newItem.setInPriceEur(newItem.getPrice());
                        newItem.setUsdplnrate(null);
                        newItem.setRatedate(null);
                        withDescription.add(newItem);
                    });
                } else {
                    withDescription.add(mainItem);
                }
            }
            eurData = withDescription;
        }

        List<ProfitCheckDTO> usdData = priceData.stream().filter(f -> "USD".equals(f.getCurrency())).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(usdData)) {
            List<ProfitCheckDTO> withDescription = new ArrayList<>();
            for (ProfitCheckDTO mainItem : usdData) {
                String key = mainItem.getExchangedate();
                if (exchangeListMap.containsKey(key)) {
                    List<ProfitCheckDTO> ProfitCheckDTOS = exchangeListMap.get(key);
                    ProfitCheckDTOS.forEach(f -> {
                        ProfitCheckDTO newItem = new ProfitCheckDTO();
                        BeanUtil.copyProperties(mainItem, newItem);
                        newItem.setUsdplnrate(f.getUsdplnrate());
                        newItem.setEurplnrate(f.getEurplnrate());
                        double pln = Math.round(newItem.getPrice() * newItem.getUsdplnrate() * 100.0) / 100.0;
                        newItem.setPln(pln);
                        newItem.setInPriceEur(null);
                        newItem.setCurrencyRate(newItem.getUsdplnrate());
                        newItem.setInPriceUsd(newItem.getPrice());
                        newItem.setEurplnrate(null);
                        newItem.setRatedate(null);
                        withDescription.add(newItem);
                    });
                } else {
                    withDescription.add(mainItem);
                }
            }
            usdData = withDescription;
        }

        List<ProfitCheckDTO> plnData = priceData.stream().filter(f -> "PLN".equals(f.getCurrency())).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(plnData)) {
            plnData.forEach(f -> {
                f.setInPriceEur(null);
                f.setInPriceUsd(null);
                f.setExchangedate(null);
                f.setPln(f.getPrice());
            });
        }

        List<ProfitCheckDTO> addExchangeData = new ArrayList<>(eurData);
        addExchangeData.addAll(usdData);
        addExchangeData.addAll(plnData);

        addExchangeData.forEach(f -> {
            f.setPrice(null);
            f.setExchangedate(null);
            f.setCurrency(null);
        });

        result.put("priceData", addExchangeData);
        result.put("noPriceData", noPriceData);
        return result;
    }

    /**
     * 减少步骤处理
     */
    private List<ProfitCheckDTO> reduceStep(List<ProfitCheckDTO> result, List<ProfitCheckDTO> outData, String reduceCol) {
        // 新的思路 - 这里的index好像可以使用id 来代表 因为后面的内容也是从他身上得来的
        for (int i = 0; i < result.size(); i++) {
            result.get(i).setIndex("" + i);
        }

        // 遍历出库数据
        for (ProfitCheckDTO row : outData) {
            String sku = row.getSku();
            int qty = row.getQty() == null ? 0 : row.getQty();

            // 按照优先级筛选不同类型的库存数据
            List<ProfitCheckDTO> resultBuySku = result.stream().filter(dto -> "买".equals(dto.getType()) && sku.equals(dto.getSku())).sorted(Comparator.comparing(ProfitCheckDTO::getInboundDate).thenComparing(ProfitCheckDTO::getInvoiceNumber)).collect(Collectors.toList());

            List<ProfitCheckDTO> resultPySku = result.stream().filter(dto -> "盘盈".equals(dto.getType()) && sku.equals(dto.getSku())).sorted(Comparator.comparing(ProfitCheckDTO::getInboundDate).thenComparing(ProfitCheckDTO::getInvoiceNumber)).collect(Collectors.toList());

            List<ProfitCheckDTO> resultBuySkuOnce = result.stream().filter(dto -> "一次性买".equals(dto.getType()) && sku.equals(dto.getSku())).sorted(Comparator.comparing(ProfitCheckDTO::getInboundDate).thenComparing(ProfitCheckDTO::getInvoiceNumber)).collect(Collectors.toList());

            List<ProfitCheckDTO> resultCgSku = result.stream().filter(dto -> "采购".equals(dto.getType()) && sku.equals(dto.getSku())).sorted(Comparator.comparing(ProfitCheckDTO::getInboundDate).thenComparing(ProfitCheckDTO::getInvoiceNumber)).collect(Collectors.toList());

            // 按优先级处理库存扣除：先扣除"买"来的货
            qty = deduct(result, reduceCol, qty, resultBuySku);
            // 再扣除"盘盈"的货
            qty = deduct(result, reduceCol, qty, resultPySku);
            // 再扣除"一次性买"的货
            qty = deduct(result, reduceCol, qty, resultBuySkuOnce);
            // 最后扣除"采购"的货
            deduct(result, reduceCol, qty, resultCgSku);
        }
        return result;
    }

    private int deduct(List<ProfitCheckDTO> result, String reduceCol, int qty, List<ProfitCheckDTO> arrayList) {
        boolean flag;
        flag = qty > 0;
        if (flag && !arrayList.isEmpty()) {
            for (ProfitCheckDTO row1 : arrayList) {
                //这里的index可以认为是他们的sku -- 如果sku唯一的话
                int endStock = row1.getEndOfMonthStock();
                String index = row1.getIndex();
                if (qty <= endStock) {
                    for (ProfitCheckDTO f : result) {
                        if (f.getIndex().equals(index)) {
                            f.setEndOfMonthStock(f.getEndOfMonthStock() - qty);
                            // 根据reduceCol参数增加相应字段的值
                            if ("transfer".equals(reduceCol)) {
                                f.setTransfer(f.getTransfer() + qty);
                            } else if ("sales".equals(reduceCol)) {
                                f.setSales(f.getSales() + qty);
                            } else if ("lost".equals(reduceCol)) {
                                f.setLost(f.getLost() + qty);
                            }
                            break; // 满足条件后跳出循环
                        }
                    }
                    qty = 0;
                } else {
                    for (ProfitCheckDTO f : result) {
                        if (f.getIndex().equals(index)) {
                            f.setEndOfMonthStock(0);
                            // 根据reduceCol参数增加相应字段的值
                            if ("transfer".equals(reduceCol)) {
                                f.setTransfer(f.getTransfer() + endStock);
                            } else if ("sales".equals(reduceCol)) {
                                f.setSales(f.getSales() + endStock);
                            } else if ("lost".equals(reduceCol)) {
                                f.setLost(f.getLost() + endStock);
                            }
                            break; // 满足条件后跳出循环
                        }
                    }
                    qty -= endStock;
                }
                if (qty == 0) break;
            }
        }
        return qty;
    }

    /**
     * 处理出库数据
     */
    private List<ProfitCheckDTO> dealOutData(List<ProfitCheckDTO> inData, String start, String end, String company) {
        List<ProfitCheckDTO> bsOut = dailyStkOrigDataCollectMapper.getBsOutData(start, end, company);
        List<ProfitCheckDTO> b2bOut = dailyStkOrigDataCollectMapper.getB2bOutData(start, end, company);
        List<ProfitCheckDTO> b2cOut = dailyStkOrigDataCollectMapper.getB2cOutData(start, end, company);
        List<ProfitCheckDTO> zyOut = dailyStkOrigDataCollectMapper.getZyOutData(start, end, company);

        List<ProfitCheckDTO> reduceZy = reduceStep(inData, zyOut, "transfer");
        List<ProfitCheckDTO> reduceB2c = reduceStep(reduceZy, b2cOut, "sales");
        List<ProfitCheckDTO> reduceB2b = reduceStep(reduceB2c, b2bOut, "sales");

        return reduceStep(reduceB2b, bsOut, "lost");
    }

    /**
     * 第二流程处理
     */
    private List<ProfitCheckDTO> secondFlow(List<ProfitCheckDTO> allData, String company) {
        // 处理转运数据 -- 这部分删除了company的值，暂时不管
        List<ProfitCheckDTO> zyData = allData.stream().filter(dto -> StrUtil.isNotBlank(dto.getFlag()) && company.equals(dto.getCompany())).map(f -> {
            // 创建新对象并复制属性
            ProfitCheckDTO newDto = new ProfitCheckDTO();
            BeanUtil.copyProperties(f, newDto);
            newDto.setIndex(f.getSku() + f.getInvoiceNumber() + f.getInboundDate() + f.getFlag());
            newDto.setCompany(null);
            return newDto;
        }).collect(Collectors.toList());


        // 这部分删除了company的值，暂时不管
        List<ProfitCheckDTO> nozyData = allData.stream().filter(dto -> StrUtil.isBlank(dto.getFlag()) && company.equals(dto.getCompany())).map(dto -> {
            // 创建新对象并复制属性
            ProfitCheckDTO newDto = new ProfitCheckDTO();
            BeanUtil.copyProperties(dto, newDto);
            newDto.setIndex(dto.getSku() + dto.getInvoiceNumber() + dto.getInboundDate());
            newDto.setCompany(null);
            newDto.setTransfer_x(newDto.getTransfer());  // 由于区分了x 和 y的区别，所以导致数据的本身默认都是_y，因为_x被单独拿出来了
            newDto.setTransfer(0);
            return newDto;
        }).collect(Collectors.toList());


        // 处理其他公司的数据
        List<ProfitCheckDTO> otherData = allData.stream().filter(dto -> dto.getTransfer() != null && dto.getTransfer() > 0 && !company.equals(dto.getCompany())).map(f -> {
            ProfitCheckDTO newItem = new ProfitCheckDTO();
            newItem.setSku(f.getSku());
            newItem.setTransfer(f.getTransfer());
            newItem.setInPriceEur(f.getInPriceEur());
            newItem.setInPriceUsd(f.getInPriceUsd());
            newItem.setCurrencyRate(f.getCurrencyRate());
            newItem.setCompany(f.getCompany());
            return newItem;
        }).collect(Collectors.toList());


        Map<String, List<ProfitCheckDTO>> descriptionDataMap = zyData.stream().collect(Collectors.groupingBy(f -> f.getSku() + f.getFlag()));
        List<ProfitCheckDTO> mergeData = new ArrayList<>();
        for (ProfitCheckDTO mainItem : otherData) {
            String key = mainItem.getSku() + mainItem.getCompany();
            if (descriptionDataMap.containsKey(key)) {
                List<ProfitCheckDTO> ProfitCheckDTOS = descriptionDataMap.get(key);
                ProfitCheckDTOS.forEach(f -> {
                    ProfitCheckDTO newItem = new ProfitCheckDTO();
                    BeanUtil.copyProperties(mainItem, newItem);
                    newItem.setIndex(f.getIndex());
                    newItem.setInvoiceNumber(f.getInvoiceNumber());
                    newItem.setInvoiceDate(f.getInvoiceDate());
                    newItem.setInboundDate(f.getInboundDate());
                    newItem.setBeginOfMonthStock(f.getBeginOfMonthStock());
                    newItem.setEndOfMonthStock(f.getEndOfMonthStock());
                    newItem.setInbound(f.getInbound());
                    newItem.setSales(f.getSales());
                    newItem.setTransfer_x(f.getTransfer());
                    newItem.setLost(f.getLost());
                    newItem.setRestock(f.getRestock());
                    newItem.setInPriceEur_x(f.getInPriceEur());
                    newItem.setInPriceUsd_x(f.getInPriceUsd());
                    newItem.setCurrencyRate_x(f.getCurrencyRate());
                    newItem.setPln(f.getPln());
                    newItem.setType(f.getType());
                    newItem.setFlag(f.getFlag());
                    mergeData.add(newItem);
                });
            } else {
                mergeData.add(mainItem);
            }
        }
        List<ProfitCheckDTO> newMergeData = mergeData.stream().filter(f -> f.getInvoiceNumber() != null && !f.getInvoiceNumber().isEmpty()).collect(Collectors.toList());


        List<ProfitCheckDTO> nodup = newMergeData.stream().collect(Collectors.groupingBy(ProfitCheckDTO::getIndex))  // 按index字段分组
                .entrySet().stream().filter(entry -> entry.getValue().size() == 1)  // 只保留只有一个元素的组（即没有重复的）
                .flatMap(entry -> entry.getValue().stream())   // 将组展平为单独的元素
                .collect(Collectors.toList());


        Set<String> nodupIndexSet = nodup.stream().map(ProfitCheckDTO::getIndex).collect(Collectors.toSet());
        List<ProfitCheckDTO> isdup = newMergeData.stream().filter(dto -> dto.getIndex() != null && !nodupIndexSet.contains(dto.getIndex())).collect(Collectors.toList());
        isdup.forEach(f -> f.setLevel_0(f.getIndex() + f.getTransfer() + f.getCurrencyRate()));


        List<ProfitCheckDTO> nodupZy;
        if (CollectionUtil.isEmpty(nodup)) {
            nodupZy = new ArrayList<>();
        } else {
            nodupZy = dealNodup(nodup);
        }


        List<ProfitCheckDTO> dupZy;
        if (CollectionUtil.isEmpty(isdup)) {
            dupZy = new ArrayList<>();
        } else {
            dupZy = dealIsdup1(isdup);
        }


        List<ProfitCheckDTO> afterDealAll = new ArrayList<>();
        afterDealAll.addAll(nozyData);
        afterDealAll.addAll(dupZy);
        //重置index
        Map<String, Integer> convertIndex = new HashMap<>();
        for (int i = 0; i < afterDealAll.size(); i++) {
            ProfitCheckDTO profitCheckDTO = afterDealAll.get(i);
            String index = profitCheckDTO.getIndex();
            if (convertIndex.get(index) != null) {
                profitCheckDTO.setIndex(String.valueOf(convertIndex.get(index)));
            } else {
                profitCheckDTO.setIndex(String.valueOf(i));
                convertIndex.put(index, i);
            }
        }
        afterDealAll.addAll(nodupZy);
        afterDealAll.forEach(f -> {
            f.setInbound(f.getInbound() == 0 ? null : f.getInbound());
            f.setSales(f.getSales() == 0 ? null : f.getSales());
            f.setLost(f.getLost() == 0 ? null : f.getLost());
            f.setRestock(f.getRestock() == 0 ? null : f.getRestock());
            f.setTransfer(f.getTransfer() == 0 ? null : f.getTransfer());
        });


        return afterDealAll;
    }

    /**
     * 处理无重复数据
     */
    private List<ProfitCheckDTO> dealNodup(List<ProfitCheckDTO> nodupResult) {
        List<ProfitCheckDTO> newZy = new ArrayList<>();

        for (ProfitCheckDTO row : nodupResult) {
            ProfitCheckDTO dto = new ProfitCheckDTO();
            dto.setSku(row.getSku());
            dto.setInvoiceNumber(row.getInvoiceNumber());
//            dto.setInvoiceDate(row.getInvoiceDate());
            dto.setInboundDate(row.getInboundDate());
            dto.setBeginOfMonthStock(row.getBeginOfMonthStock() != null ? row.getBeginOfMonthStock() : 0);
            dto.setEndOfMonthStock(row.getEndOfMonthStock() != null ? row.getEndOfMonthStock() : 0);
            dto.setInbound(row.getInbound() != null ? row.getInbound() : 0);
            dto.setSales(row.getSales() != null ? row.getSales() : 0);
            dto.setTransfer(row.getTransfer_x() != null ? row.getTransfer_x() : 0);
            dto.setLost(row.getLost() != null ? row.getLost() : 0);
            dto.setRestock(row.getRestock() != null ? row.getRestock() : 0);
            dto.setInPriceEur(row.getInPriceEur());
            dto.setInPriceUsd(row.getInPriceUsd());
            dto.setCurrencyRate(row.getCurrencyRate());

            // 计算PLN值
            double pln = 0.0;
            if (row.getInPriceEur() != null && row.getInPriceEur() != 0.0) {
                pln = Math.round(row.getInPriceEur() * row.getCurrencyRate() * 100.0) / 100.0;
            } else if (row.getInPriceUsd() != null && row.getInPriceUsd() != 0.0) {
                pln = Math.round(row.getInPriceUsd() * row.getCurrencyRate() * 100.0) / 100.0;
            }
            dto.setPln(pln);
            dto.setType("买");

            newZy.add(dto);
        }

        return newZy;
    }

    /**
     * 处理重复数据1
     */
    private List<ProfitCheckDTO> dealIsdup1(List<ProfitCheckDTO> dupResult) {

        // 按 index 和 level0 排序
        dupResult = dupResult.stream().sorted(Comparator.comparing(ProfitCheckDTO::getIndex).thenComparing(ProfitCheckDTO::getLevel_0)).collect(Collectors.toList());

        dupResult.forEach(f -> {
            f.setEndOfMonthStock(null);
            if (f.getInPriceEur() != null && f.getInPriceEur() != 0.0) {
                double pln = Math.round(f.getInPriceEur() * f.getCurrencyRate() * 100.0) / 100.0;
                f.setPln(pln);
            } else {
                f.setPln(null);
            }
            if (f.getInPriceUsd() != null && f.getInPriceUsd() != 0.0) {
                double pln = Math.round(f.getInPriceUsd() * f.getCurrencyRate() * 100.0) / 100.0;
                f.setPln(pln);
            } else {
                f.setPln(null);
            }
            f.setTransfer_x(null);
            f.setInPriceEur_x(null);
            f.setCurrencyRate_x(null);
            f.setCompany(null);
        });

        return dupResult;
    }

    /**
     * 写入CSV文件（第二流程）
     *
     * @param data     数据列表
     * @param filePath 文件路径
     */
    private void writeSecondFlowCsvFile(List<ProfitCheckDTO> data, String filePath) {
        try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(Files.newOutputStream(Paths.get(filePath)), "GBK"))) {
            // 写入表头
            pw.println(String.join(",", SECOND_COLUMNS));

            // 写入数据行
            for (ProfitCheckDTO dto : data) {
                pw.println(formatSecondFlowCsvRow(dto));
            }

            log.info("数据已成功写入CSV文件: {}", filePath);
        } catch (IOException e) {
            log.error("写入CSV文件时出错: {}", filePath, e);
        }
    }

    /**
     * 格式化第二流程CSV数据行
     *
     * @param item 数据项
     * @return 格式化后的CSV行字符串
     */
    private String formatSecondFlowCsvRow(ProfitCheckDTO item) {
        List<String> values = new ArrayList<>();
        values.add(item.getIndex() != null ? item.getIndex() : "");
        WriteCommonCVS(item, values);
        values.add(item.getLevel_0() != null ? item.getLevel_0() : "");
        values.add(String.valueOf(item.getInPriceUsd_x() != null && item.getInPriceUsd_x() > 0 ? item.getInPriceUsd_x() : ""));
        values.add(String.valueOf(item.getTransfer() != null && item.getTransfer() > 0 ? item.getTransfer() : ""));
        // 转义包含逗号或引号的字段，并用引号包围
        return values.stream().map(this::escapeCsvField).collect(Collectors.joining(","));
    }

    // 写报表CVS文件公共部分
    private void WriteCommonCVS(ProfitCheckDTO item, List<String> values) {
        values.add(item.getSku() != null ? item.getSku() : "");
        values.add(item.getInvoiceNumber() != null ? item.getInvoiceNumber() : "");
        values.add(item.getInvoiceDate() != null ? item.getInvoiceDate() : "");
        values.add(item.getInboundDate() != null ? item.getInboundDate() : "");
        values.add(String.valueOf(item.getBeginOfMonthStock() != null && item.getBeginOfMonthStock() >= 0 ? item.getBeginOfMonthStock() : ""));
        values.add(String.valueOf(item.getEndOfMonthStock() != null && item.getEndOfMonthStock() >= 0 ? item.getEndOfMonthStock() : ""));
        values.add(String.valueOf(item.getInbound() != null && item.getInbound() > 0 ? item.getInbound() : ""));
        values.add(String.valueOf(item.getSales() != null && item.getSales() > 0 ? item.getSales() : ""));
        values.add(String.valueOf(item.getTransfer_x() != null && item.getTransfer_x() > 0 ? item.getTransfer_x() : ""));
        values.add(String.valueOf(item.getLost() != null && item.getLost() > 0 ? item.getLost() : ""));
        values.add(String.valueOf(item.getRestock() != null && item.getRestock() > 0 ? item.getRestock() : ""));
        values.add(item.getInPriceEur() != null && item.getInPriceEur() > 0 ? String.valueOf(item.getInPriceEur()) : "");
        values.add(item.getInPriceUsd() != null && item.getInPriceUsd() > 0 ? String.valueOf(item.getInPriceUsd()) : "");
        values.add(item.getCurrencyRate() != null && item.getCurrencyRate() > 0 ? String.valueOf(item.getCurrencyRate()) : "");
        values.add(item.getPln() != null && item.getPln() > 0 ? String.valueOf(item.getPln()) : "");
        values.add(item.getType() != null ? item.getType() : "");
        values.add(item.getFlag() != null ? item.getFlag() : "");
    }

    /**
     * 转义CSV字段
     *
     * @param field 字段值
     * @return 转义后的字段值
     */
    private String escapeCsvField(String field) {
        if (field == null) {
            return "";
        }
        // 如果字段包含逗号、换行符或双引号，则需要用双引号包围，并将双引号转义为两个双引号
        if (field.contains(",") || field.contains("\"") || field.contains("\n")) {
            return "\"" + field.replace("\"", "\"\"") + "\"";
        }
        return field;
    }


    // 报表入库处理


    /**
     * 比较报表数据和库存数据是否一致
     */
    public void checkProfitKc(String date){
        List<CheckProfitBO> checkProfitList = profitCheckMapper.getCheckProfitList(date);
        checkProfitList.forEach(f->f.setBelongs(f.getBelongs().toUpperCase()));
        List<CheckProfitBO> checkKcList = tempKcjlDailyMapper.getCheckKcList(date);
        Map<String, Integer> kcMap = checkKcList.stream().collect(Collectors.toMap(l ->
                l.getSku() + l.getBelongs() + l.getDate(), CheckProfitBO::getNum));
        for (CheckProfitBO bo : checkProfitList) {
            String key = bo.getSku() + bo.getBelongs() + bo.getDate();
            Integer num = kcMap.get(key);
            if(num == null){
                log.error("此库存数据不存在：{}",bo);
                throw new RuntimeException("此库存数据不存在："+bo);
            }
            if(!Objects.equals(bo.getNum(), num)){
                log.error("此数据的库存不一致,库存记录num的值为:{}，报表的num值为：{}，报表数据为{}",num,bo.getNum(),bo);
                throw new RuntimeException("此数据的库存不一致,库存记录num的值为:"+num+" ，报表的num值为："+bo.getNum()+"报表的数据为："+bo);
            }
        }
        log.info("【 {} 】利润检查表数据校验通过",date);
    }

    /**
     * 读取利润检查表数据并生成CVS文件
     * @param date
     */
    public void getDataByDate(String date){
        List<ProfitCheckDTO> dataByDate = profitCheckMapper.getDataByDate(date);

        String replace = date.replace("-", "");
        String filePath = PATH + replace + "利润检查表.csv";

        try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(Files.newOutputStream(Paths.get(filePath)), "GBK"))) {
            // 写入表头
            pw.println(String.join(",", PROFIT_COLUMNS));

            // 写入数据行
            for (ProfitCheckDTO dto : dataByDate) {
                List<String> values = new ArrayList<>();
                WriteCommonCVS(dto, values);
                values.add(dto.getCompany() != null ? dto.getCompany() : "");
                pw.println(values.stream().map(this::escapeCsvField).collect(Collectors.joining(",")));
            }

            log.info("数据已成功写入CSV文件: {}", filePath);
        } catch (IOException e) {
            log.error("写入CSV文件时出错: {}", filePath, e);
        }

    }


    /**
     * 处理后的报表数据入库
     *
     * @param date 入指定时间的数据
     */
    public void insertData(String date) {

        String name = "profitCheckInsert-05";
        DailyAuditStatus dailyAuditStatus = statusMapper.selectStatus(name, date);
        if (dailyAuditStatus != null && dailyAuditStatus.getFlag() == 1) {
            log.info("{} - 该方法已执行，进行跳过！", name);
            return;
        }

        // 获取当前代理对象
        ProfitCheck proxy = (ProfitCheck) AopContext.currentProxy();
        for (String company : COMPANY_LIST) {

            List<ProfitCheckDTO> List = commonService.readCsvDataFromProfitCheck(date, company);
            List<ProfitStatement> allData = profitCheckMapper.getAllData(company);

            if (CollectionUtil.isEmpty(allData)) {
                proxy.batchInsert(List, company, date);
            } else {
                Map<String, ProfitStatement> allKeys = allData.stream().collect(Collectors.toMap(f -> f.getSku() + "|" + f.getInvoiceNo(), f -> f));
                Map<Boolean, List<ProfitCheckDTO>> partitioned = List.stream()
                        .collect(Collectors.partitioningBy(f -> allKeys.containsKey(f.getSku() + "|" + f.getInvoiceNumber())));

                // 存在相同的数据 - 这里指的是相同的sku和发票号
                List<ProfitCheckDTO> existKeysList = partitioned.get(true);
                List<ProfitCheckDTO> noExistKeysList = partitioned.get(false);

                if (CollectionUtil.isNotEmpty(existKeysList)) {
                    proxy.UpdateAndInsert(company, date, existKeysList, allKeys);
                }

                if (CollectionUtil.isNotEmpty(noExistKeysList)) {
                    proxy.batchInsert(noExistKeysList, company, date);
                }

            }
        }

		// 修改执行状态
		commonService.UpdateOrInsertStatus(dailyAuditStatus, name, date);

        log.info("{}日的报表数据生成完毕",date);

    }

    /**
     * 更新利润总数据并新增日数据、报表
     */
    @Transactional
    public void UpdateAndInsert(String company, String date, List<ProfitCheckDTO> existKeysList, Map<String, ProfitStatement> allKeys) {
        List<ProfitStatement> profitCheckList = new LinkedList<>();
        List<ProfitCheckRecord> profitCheckRecordList = new LinkedList<>();
        List<ProfitStatementDaily> profitCheckDailyList = new LinkedList<>();
        Map<String, List<ProfitCheckDTO>> profitCheckMap = existKeysList.stream()
                .collect(Collectors.groupingBy(p -> p.getSku() + "|" +
                        (StringUtils.isNotBlank(p.getInvoiceNumber()) ? p.getInvoiceNumber() : "")));
        profitCheckMap.remove("null");

        profitCheckMap.forEach((k, v) -> {
            String id = allKeys.get(k).getId();
            dealProfitDailyAndRecord(company, date, v, id, profitCheckRecordList, profitCheckDailyList, profitCheckList);
        });

        profitCheckList.forEach(f->{
            System.out.println(f.getId()+"  "+f.getRemainingNum());
        });

        profitCheckMapper.batchUpdateProfitCheck(profitCheckList);
        profitCheckMapper.batchSaveProfitCheckDaily(profitCheckDailyList);
        profitCheckMapper.batchSaveRecord(profitCheckRecordList);
    }

    /**
     * 新增利润总数据、日数据、报表
     */
    @Transactional
    public void batchInsert(List<ProfitCheckDTO> List, String company, String date) {
        List<ProfitStatement> profitCheckList = new LinkedList<>();
        List<ProfitCheckRecord> profitCheckRecordList = new LinkedList<>();
        List<ProfitStatementDaily> profitCheckDailyList = new LinkedList<>();
        Map<String, List<ProfitCheckDTO>> profitCheckMap = List.stream()
                .collect(Collectors.groupingBy(p -> p.getSku() +
                        (StringUtils.isNotBlank(p.getInvoiceNumber()) ? p.getInvoiceNumber() : "")));
        profitCheckMap.remove("null");
        profitCheckMap.forEach((k, v) -> {
            String id = identifierGenerator.nextId(new ProfitCheck()).toString();
            dealProfitDailyAndRecord(company, date, v, id, profitCheckRecordList, profitCheckDailyList, profitCheckList);
        });

        profitCheckMapper.batchSaveProfitCheck(profitCheckList);
        profitCheckMapper.batchSaveProfitCheckDaily(profitCheckDailyList);
        profitCheckMapper.batchSaveRecord(profitCheckRecordList);
    }

    /**
     * 处理利润日数据和报表数据数据
     *
     * @param company               货权
     * @param date                  当天时间
     * @param v                     sku+invcoiceNo数据集
     * @param id                    唯一id
     * @param profitCheckRecordList 报表集合
     * @param profitCheckDailyList  日利润明细集合
     * @param profitCheckList       利润表集合
     */
    private static void dealProfitDailyAndRecord(String company, String date, List<ProfitCheckDTO> v, String id, List<ProfitCheckRecord> profitCheckRecordList, List<ProfitStatementDaily> profitCheckDailyList, List<ProfitStatement> profitCheckList) {
        int remainingNum = v.stream().mapToInt(ProfitCheckDTO::getEndOfMonthStock).sum();
        int beginStockNum = v.stream().mapToInt(ProfitCheckDTO::getBeginOfMonthStock).sum();

        ProfitStatement profitCheck = ProfitStatement.builder()
                .id(id)
                .sku(v.get(0).getSku())
                .invoiceNo(v.get(0).getInvoiceNumber())
                .belongs(company)
                .date(date)
                .remainingNum(remainingNum)
                .createTime(LocalDateTime.now()).build();

        ProfitStatementDaily profitCheckDaily = ProfitStatementDaily.builder()
                .profitCheckId(id)
                .date(date)
                .flag(beginStockNum != remainingNum)
                .beginStockNum(beginStockNum)
                .endStockNum(remainingNum).build();

        // 为record进行分组，优先以pln 因为pln是根据eur+rate/usd+rate得来的，几乎不存在不同的数据混在一起
        Map<String, List<ProfitCheckDTO>> recordMap = v.stream()
                .collect(Collectors.groupingBy(dto -> {
                    if (dto.getPln() != null) {
                        return dto.getPln().toString();
                    } else if (dto.getInPriceEur() != null) {
                        return dto.getInPriceEur() +"|"+ dto.getCurrencyRate();
                    } else if (dto.getInPriceUsd() != null) {
                        return dto.getInPriceUsd() +"|"+ dto.getCurrencyRate();
                    } else if (dto.getCurrencyRate() != null) {
                        return dto.getCurrencyRate().toString();
                    }
                    return "null"; // 默认值
                }));
        if(recordMap.containsKey("null")){
            log.error("存在异常数据：{}", recordMap.get("null"));
            throw new RuntimeException("存在异常数据"+recordMap.get("null"));
        }

        recordMap.forEach((k1, l1) -> {
            int endStockNum1 = l1.stream().mapToInt(d -> d.getEndOfMonthStock() != null ? d.getEndOfMonthStock() : 0).sum();
            int beginStockNum1 = l1.stream().mapToInt(d -> d.getBeginOfMonthStock() != null ? d.getBeginOfMonthStock() : 0).sum();
            int inBoundNum = l1.stream().mapToInt(d -> d.getInbound() != null ? d.getInbound() : 0).sum();
            int salesNum = l1.stream().mapToInt(d -> d.getSales() != null ? d.getSales() : 0).sum();
            int transferNum = l1.stream().mapToInt(d -> d.getTransfer() != null ? d.getTransfer() : 0).sum();
            int lostNum = l1.stream().mapToInt(d -> d.getLost() != null ? d.getLost() : 0).sum();
            int restockNum = l1.stream().mapToInt(d -> d.getRestock() != null ? d.getRestock() : 0).sum();

            ProfitCheckRecord record = ProfitCheckRecord.builder()
                    .profitCheckId(id).
                    invoiceDate(l1.get(0).getInvoiceDate() != null ? l1.get(0).getInvoiceDate() : "").
                    inboundDate(l1.get(0).getInboundDate() != null ? l1.get(0).getInboundDate() : "").
                    beginStockNum(beginStockNum1).
                    endStockNum(endStockNum1).
                    inbound(inBoundNum).
                    sales(salesNum).
                    transfer(transferNum).
                    lost(lostNum).
                    restock(restockNum).
                    inPriceEur(l1.get(0).getInPriceEur()).
                    inPriceUsd(l1.get(0).getInPriceUsd()).
                    currencyRate(l1.get(0).getCurrencyRate()).
                    pln(l1.get(0).getPln()).
                    type(l1.get(0).getType()).
                    date(date).build();
            profitCheckRecordList.add(record);
        });

        profitCheckDailyList.add(profitCheckDaily);
        profitCheckList.add(profitCheck);
    }

}
